home *** CD-ROM | disk | FTP | other *** search
/ PC Media 2 / PC MEDIA CD02.iso / share / udos / kack10 / kack.8 < prev    next >
Encoding:
Text File  |  1992-07-11  |  19.7 KB  |  481 lines

  1. ;
  2. ; KACK.8:  Key Accecelerator and Key Clicker by G. Vanem 1992
  3. ;          Use A86 3+ to assemble. A86 is an product of Eric Isacsson
  4. ;          (probably the fastest assembler in the world)
  5.  
  6. CODE SEGMENT
  7.               ORG 100h
  8.               JMP Main
  9. Start         = $                 ; offset 103h
  10. NewStart      = 50h               ; final start of code (in PSP)
  11. Delta         = Start - NewStart  ; distance to move code = 179 bytes
  12. ClickPeriod   = 1000              ; Default tone period for key-click.
  13. MinPeriod     = 100
  14. MaxPeriod     = 10000
  15. NoOp          = 90h               ; NOP opcode
  16. True          =  1
  17. False         =  0
  18. CR            = 13
  19. LF            = 10
  20.  
  21. ; Resident constants and variables
  22.  
  23. OldInt9       DD ?                ; pointer to old int 9 routine
  24. SpeedFactor   DW ?                ; CX value for a 8 cycle empty loop to
  25.                                   ; complete in 1ms
  26. MemMarker     DW 'VG'             ; memory marker
  27. BIOSSeg       DW 40h
  28.  
  29. ;-----------------------------------------------------------------------------
  30. ; play a note with 1ms duration
  31.  
  32. Click:        MOV AL,10110110b               ; 10  = timer 2
  33.                                              ; 11  = lsb followed by msb
  34.                                              ; 011 = square wave generator
  35.                                              ; 0   = binary 8bit value
  36.               OUT 43h,AL
  37.               MOV AL,Low(ClickPeriod)        ; AL = low byte (lsb)
  38. ClickP_LO = $ - 1                            ; lsb patch point
  39.               OUT 42h,AL
  40.               MOV AL,High(ClickPeriod)       ; AL = high byte (msb)
  41. ClickP_HI = $ - 1                            ; msb patch point
  42.               OUT 42h,AL
  43.               IN AL,61h
  44.               OR AL,3                        ; turn on speaker bit
  45.               OUT 61h,AL
  46.  
  47.               PUSH CX
  48.               MOV CX,[SpeedFactor-Delta]     ; delay factor
  49.               EVEN
  50. Cloop:        LOOP Cloop                     ; wait 1ms
  51.               POP CX
  52.  
  53.               IN AL,61h
  54.               AND AL,11111100b               ; turn speaker bit off
  55.               OUT 61h,AL
  56.               RET
  57.  
  58. ;-----------------------------------------------------------------------------
  59.  
  60. Int9_ISR:     PUSHF                    ; save flag register
  61.               PUSH AX                  ; save register to use
  62.               STI                      ; disable interrupts
  63.               IN AL,60h                ; read keyboard I/O port
  64.               TEST AL,10000000b        ; test high-bit (key release)
  65.               JNZ ExitISR              ; if set then exit
  66.               PUSH DS                  ; save DS
  67.               PUSH CS:[BIOSseg-Delta]
  68.               POP DS                   ; DS = BIOS segment = 40h
  69.               TEST B[17h],00001111b    ; shift status: alt, ctrl or shifts ?
  70.               JNZ NoClick              ; yes, make no click
  71.               PUSH CS
  72.               POP DS                   ; DS = CS
  73.               CALL Click               ; make click sound
  74. NoClick:      POP DS
  75.  
  76. ExitISR:      POP AX
  77.               POPF
  78.               JMP CS:[OldInt9-Delta]   ; jump to the old int 9 routine
  79.  
  80. ISRend = $ + 1                         ; end of resident code and data
  81.  
  82. ;------------------------------------------------------------------------------
  83. ;
  84. ; Non- resident variables and constants
  85. ;
  86.  
  87. KeySpeed      DB 5                ; fastest key repetition
  88. CPU286        DB False            ; no 80286 (AT) found yet
  89. InstClick     DB False            ; false to install click procedure
  90. ChangeSpeed   DB False            ; false to change typematic rate
  91. ChangePeriod  DB False            ; false to change period
  92. InMem         DB False            ; program not in memory
  93. InHiMem       DB False            ; program not above 640k limit
  94. MemSeg        DW 80h              ; segment of resident program. Start of search
  95.  
  96. ProgName      DB ' KACK by G. Vanem 1992',CR,LF,'$'
  97. FormatErrMsg  DB ' Error in argument /Px.',7,CR,LF,CR,LF
  98. UsageMsg      DB ' Usage: KACK /<C n Px U>',CR,LF
  99.               DB '        /C for key Clicks',CR,LF
  100.               DB '        /n (1..4) keyspeed',CR,LF
  101.               DB '        /P x = tone period (100..10000)',CR,LF,
  102.               DB '        /U unload from memory',CR,LF,'$'
  103. RemoveMsgLo   DB ' KACK removed from low-memory.',CR,LF,'$'
  104.  
  105. ;
  106. ; Error messages
  107. ;
  108.  
  109. IllegalMsg    DB ' Illegal parameter.',7,CR,LF,'$'
  110. NotInstMsg    DB ' KACK is not resident.',CR,LF,'$'
  111. AlreadyInstLo DB ' KACK is already resident in low memory.',CR,LF,'$'
  112. AlreadyInstHi DB ' KACK is already resident in high memory.',CR,LF,'$'
  113. FreeEnvErr    DB ' Cannot remove; environment block is bad.',CR,LF,'$'
  114. RemoveMsgHi   DB ' KACK removed from high-memory.',CR,LF,'$'
  115. RemoveErrMsg1 DB ' KACK cannot be removed from memory',CR,LF
  116.               DB ' because vector 9 has changed.',CR,LF,'$'
  117. RemoveErrMsg2 DB ' KACK cannot be removed from memory',CR,LF
  118.               DB ' because memory control block is destroyed.',CR,LF,'$'
  119. RemoveErrMsg3 DB ' KACK cannot be removed from memory',CR,LF
  120.               DB ' because of invalid memory block address.',CR,LF,'$'
  121. NoATmsg       DB ' Cannot set typematic rate.',CR,LF
  122.               DB ' Needs AT or better.',7,CR,LF,'$'
  123. Period2HiMsg  DB ' Period too high, max. 10000.',7,CR,LF,'$'
  124. Period2LoMsg  DB ' Period too low, min. 100.',7,CR,LF,'$'
  125.  
  126. ; *****
  127.  
  128. SpeedMsg      DB ' Key repeat rate is $'
  129. SpeedMsg1     DB '7.5 cps.',CR,LF,'$'
  130. SpeedMsg2     DB '10 cps.',CR,LF,'$'
  131. SpeedMsg3     DB '15 cps.',CR,LF,'$'
  132. SpeedMsg4     DB '30 cps.',CR,LF,'$'
  133. MsgOfs        DW SpeedMsg1, SpeedMsg2, SpeedMsg3, SpeedMsg4
  134. KeySpeedTable DB 0,16,10,5,1
  135.  
  136. ArgPtr:       DB '?hHcCpPuU1234 -/',CR      ; possible command line characters
  137. NumArgs       = $ - ArgPtr                  ; length of argument string
  138.               EVEN                          ; argument dispatchers
  139. ArgTable:     DW Arg_H,     Arg_H,     Arg_H,     Arg_C,   Arg_C
  140.               DW Arg_P,     Arg_P,     Arg_U,     Arg_U
  141.               DW Arg_n,     Arg_n,     Arg_n,     Arg_n
  142.               DW Arg_Next,  Arg_Next,  Arg_Next,  Arg_CR
  143.  
  144. ;------------------------------------------------------------------------------
  145.  
  146. GetCPUspeed:  PUSH DS                  ; save data segment
  147.               PUSH BIOSseg
  148.               POP DS                   ; DS = BIOS segment
  149.               MOV BX,W[6Ch]            ; get timer low word
  150.               INC BX                   ; BX = 1 + current time
  151.               EVEN
  152. Bloop:        CMP W[6Ch],BX            ; timer = BX ?
  153.               JNE Bloop                ; wait till timer has updated
  154.               INC BX                   ; add 55ms
  155.               XOR CX,CX
  156.               EVEN
  157. Dloop:        DB 12 DUP (NoOp)  ;36 clk (12 x NOP) (filler op-codes)
  158.               ROR AX,1          ; 2 clk            (filler op-codes)
  159.               ROR AX,1          ; 2 clk            (filler op-codes)
  160.               INC CX            ; 2 clk
  161.               CMP W[6Ch],BX     ; 6 clk            55ms elapsed ?
  162.               JNE Dloop         ; 7 clk = 55 clk
  163.  
  164.               POP DS
  165.               SHR CX,1
  166.               SHR CX,1                 ; divide by 8
  167.               SHR CX,1
  168.               MOV SpeedFactor,CX       ; save CX as speed factor
  169.               RET
  170.  
  171. ;-----------------------------------------------------------------------------
  172. ;
  173. ; Check to see if this PC has a 80286 processor or better
  174. ; Output: Carry = 1, no 80286
  175. ;         Carry = 0, 80286 or better
  176.  
  177. GetCPUtype:   XOR BX,BX                ; BX = 0
  178.               PUSH BX                  ; save it onto stack
  179.               POPF                     ; pop flags
  180.               PUSHF                    ; save flags
  181.               POP BX                   ; BX = flags
  182.               AND BX,0F000H            ; mask upper 4 bits
  183.               CMP BX,0F000H
  184.               JZ RET                   ; if zero flag set, then < 80286
  185.               MOV CPU286,True
  186.               RET
  187.  
  188. ;-----------------------------------------------------------------------------
  189.  
  190. SearchLoMem:  INC MemSeg               ; increment segment
  191.               PUSH MemSeg
  192.               POP ES                   ; ES = MemSeg
  193.               CLC
  194.               CMP AX,MemSeg            ; CS = MemSeg ?
  195.               JE RET                   ; yes, then exit
  196.               LEA SI,MemMarker         ; DS:SI -> this memory marker
  197.               LEA DI,MemMarker-Delta   ; ES:DI -> old memory marker
  198.               MOV CX,8                 ; compare the 8 first bytes
  199.               CLD                      ; forward string compare
  200.               REP CMPSB                ; compare 8 bytes
  201.               JNE SearchLoMem          ; if not equal then next segment
  202.               STC                      ; set carry
  203.               MOV InMem,True           ; already installed
  204.               RET
  205.  
  206. SearchHiMem:  DEC MemSeg               ; decrement segment
  207.               PUSH MemSeg
  208.               POP ES                   ; ES = MemSeg
  209.               CMP AX,MemSeg            ; CS = MemSeg ?
  210.               JE RET                   ; yes, then exit
  211.               LEA SI,MemMarker         ; DS:SI -> this memory marker
  212.               LEA DI,MemMarker-Delta   ; ES:DI -> old memory marker
  213.               MOV CX,8                 ; compare the 8 first bytes
  214.               CLD                      ; forward string compare
  215.               REP CMPSB                ; compare 8 bytes
  216.               JNE SearchHiMem          ; if not equal then next segment
  217.               MOV InMem,True           ; already installed
  218.               MOV InHiMem,True
  219.               RET
  220.  
  221. ;--------------------------------------------------------------------------
  222. ;
  223. ;  GetPeriod; fetch the number after /P. Change code to new tone period
  224. ;
  225. TempStr       DB 0,0,0,0,0
  226. AntiLog       DW 1, 10, 100, 1000, 10000
  227.  
  228. GetPeriod:    PUSH DS
  229.               POP ES
  230.               LEA DI,TempStr           ; ES:DI -> end of temporary string
  231.               XOR BX,BX                ; use BX as digit counter
  232.               CLD
  233. GetNextP:     LODSB                    ; get next
  234.               CMP AL,' '               ;
  235.               JE Convert
  236.               CMP AL,CR
  237.               JE Convert
  238.               CMP AL,'0'
  239.               JB FormatError
  240.               CMP AL,'9'
  241.               JA FormatError
  242.               SUB AL,'0'               ; save as BCD number
  243.               STOSB                    ; save it in TempStr
  244.               INC BX                   ; increment length
  245.               JMP GetNextP
  246.  
  247. FormatError:  LEA DX,FormatErrMsg
  248.               STC
  249.               RET
  250.  
  251. Convert:      SHL BX,1
  252.               MOV AL,TempStr[1]
  253.               MOV AH,TempStr[0]
  254.               AAD                      ; AX = 10*AH + AL
  255.               MUL AntiLog[BX-4]
  256.               MOV CX,AX                ; save 2 last digits
  257.               MOV AL,TempStr[3]
  258.               MOV AH,TempStr[2]
  259.               AAD
  260.               MUL AntiLog[BX-8]
  261.               ADD CX,AX
  262.               ADD CL,TempStr[4]
  263.               ADC CX,0
  264.  
  265.               DEC SI                  ; point to last char analysed
  266.               STC
  267.               CMP CX,MaxPeriod
  268.               JBE ChkLoPeriod
  269.               LEA DX,Period2HiMsg
  270.               RET
  271. ChkLoPeriod:  CMP CX,MinPeriod
  272.               JAE PeriodOk
  273.               LEA DX,Period2LoMsg
  274.               RET
  275.  
  276. PeriodOk:     XOR BX,BX
  277.               PUSH DS
  278.               CMP InMem,True
  279.               JNE NoChangeTSR
  280.               PUSH MemSeg
  281.               POP DS                   ; DS = TSR segment
  282.               MOV BX,-Delta
  283. NoChangeTSR:  MOV ClickP_LO[BX],CL
  284.               MOV ClickP_HI[BX],CH
  285.               POP DS
  286.               CLC
  287.               RET
  288.  
  289. ;******************** MAIN ENTRY POINT **************************************
  290.  
  291. Main:         CMP B[80h],0             ; zero length command line
  292.               JE Arg_H                 ; then show help
  293.               CALL GetCPUspeed         ; get speed factor of this PC
  294.               CALL GetCPUtype          ; is this an AT ?
  295.               NOT W[MemMarker]         ; initialize finger print
  296.               MOV AX,CS                ; AX = current segment
  297.               CALL SearchLoMem         ; search low memory
  298.               JC GetArgs               ; if found, jump
  299.               MOV MemSeg,0FFFFh        ; start at top segment
  300.               CALL SearchHiMem         ; else, search high memory
  301.  
  302. GetArgs:      MOV SI,81h               ; DS:SI -> command line (1st char)
  303.               CLD
  304.               PUSH DS
  305.               POP ES                   ; ES = DS
  306. NextArg:      CALL Arg_Next            ; get address of action procedure
  307.               CALL DS:ArgTable[DI]     ; call it
  308.               JMP NextArg
  309.  
  310. Arg_Next:     MOV DI,ArgPtr
  311.               MOV CX,NumArgs
  312.               LODSB                    ; AL = DS:SI, SI=SI+1
  313.               REPNE SCASB              ; find AL in possible arguments
  314.               JNE IllegalArg           ; exit if not found
  315.               SUB DI,ArgPtr+1          ; found, DI = offset of character
  316.               ADD DI,DI                ; make word offset
  317.               RET
  318.  
  319. IllegalArg:   LEA DX,IllegalMsg
  320.               MOV AX,0900h
  321.               INT 21h
  322.  
  323. Arg_H:        POP AX                   ; fix stack
  324.               LEA DX,UsageMsg          ; print help message
  325.               JMP DOSexit
  326.  
  327. Arg_C:        MOV InstClick,True       ; true to install TSR
  328.               RET
  329.  
  330. Arg_n:        SUB AL,'0'               ; make binary
  331.               MOV KeySpeed,AL          ; save requested key speed
  332.               CALL QuickKey            ; set typematic rate
  333.               JNC RET                  ; carry clear, exit
  334.               POP AX                   ; fix stack
  335.               JMP DOSexit              ; write error message ("no AT")
  336.               RET
  337.  
  338. Arg_P:        CALL GetPeriod
  339.               JNC RET
  340.               POP AX                   ; fix stack
  341.               JMP DOSexit
  342.  
  343. Arg_U:        POP AX                   ; fix stack
  344.               LEA DX,NotInstMsg        ; "KACK is not resident"
  345.               CMP InMem,1              ; in memory ?
  346.               JNE DOSexit              ; no, write and exit
  347.               PUSH MemSeg
  348.               POP ES                   ; yes, ES = segment to release
  349.               CALL RemoveISR           ; remove code 
  350.               JC DOSexit               ; carry set = error
  351.               LEA DX,RemoveMsgHi       ; "KACK removed from high memory"
  352.               CMP InHiMem,True         ; resident above 640k limit ?
  353.               JE DOSexit               ; yes, jump
  354.               LEA DX,RemoveMsgLo       ; no, "KACK removed from low memory"
  355.               JMP DOSexit
  356.  
  357. Arg_CR:       POP AX                   ; fix stack
  358.               CMP InstClick,1          ; if /C was entered then install TSR
  359.               JE ClickInst
  360.               XOR DX,DX                ; write nothing
  361.  
  362. DOSexit:      CMP DX,0                 ; if DX = 0
  363.               JE NoWrite               ; then write nothing
  364.               MOV AH,9                 
  365.               INT 21h                  ; write through DOS
  366. NoWrite:      MOV AX,4C00h             ; exit to DOS
  367.               INT 21h
  368.  
  369. ;-----------------------------------------------------------------------------
  370.  
  371. ClickInst:    LEA DX,AlreadyInstHi     ; ".. already resident in high memory"
  372.               CMP InHiMem,True         ; resident in high memory ?
  373.               JE DOSexit               ; yes, exit
  374.               LEA DX,AlreadyInstLo     ; ".. already resident in low memory"
  375.               CMP InMem,1              ; resident in low memory ?
  376.               JE DOSexit               ; yes, exit
  377.  
  378.               MOV ES,W[2Ch]            ; get environment block address from PSP
  379.               MOV AH,49h               ; free block function
  380.               LEA DX,FreeEnvErr
  381.               INT 21h                  ; free environment block
  382.               JC DOSexit               ; jump if error freeing environment
  383.  
  384.               MOV AX,3509h
  385.               INT 21h                  ; get int 9 vector
  386.               MOV W[OldInt9  ],BX      ; save offset of int 9 ISR
  387.               MOV W[OldInt9+2],ES      ; save segment of int 9 ISR
  388.               MOV AX,2509h
  389.               LEA DX,Int9_ISR-Delta    ; DS:DX -> our ISR
  390.               INT 21h                  ; set interrupt vector
  391.  
  392.               PUSH DS
  393.               POP ES                   ; ES = DS
  394.               MOV DI,NewStart          ; move to offset 50h
  395.               MOV SI,Start             ; move from offset 103h
  396.               MOV CX,ISRend - Start    ; number of bytes to move
  397.               CLD
  398.               REP MOVSB                ; copy code and data
  399.  
  400.               LEA DX,ProgName          ; print install message
  401.               MOV AH,9
  402.               INT 21h
  403.               MOV AX,3100h
  404.               MOV DX,(ISRend-Delta+15)/16 ; # of paragraphs to keep
  405.               INT 21h                  ; terminate and stay resident
  406.  
  407.  
  408. ; RemoveISR: removes the resident program from memory
  409. ;  Input:   ES = segment to release
  410. ;  output:  CF = 0 program removed
  411. ;           CF = 1 cannot remove
  412. ;           BX = error number:
  413. ;                1 = vector 9 changed.
  414. ;                7 = memory control block destroyed
  415. ;                9 = invalid memory block address
  416.  
  417. RemoveISR:    MOV CX,ES                ; save ES
  418.               MOV AX,3509h             ; get vector address
  419.               INT 21h
  420.               MOV AX,ES                ; AX = segment of ISR
  421.               STC
  422.               LEA DX,RemoveErrMsg1
  423.               CMP AX,CX                ; compare old ES and new ES
  424.               JNE RET                  ; error if not equal, return CF=1
  425.               MOV ES,CX                ; ES = segment to release
  426.               MOV AH,49h               ; release segment
  427.               INT 21h
  428.               JC RemoveErr             ; if error, jump
  429. FreeOK:       NOT ES:W[MemMarker-Delta]; destroy our finger print
  430.               MOV AX,2509h             ; set interrupt vector
  431.               PUSH DX
  432.               PUSH DS                  ; save DX and DS
  433.               LDS DX,ES:[OldInt9-Delta]; DS:DX = old int 9 address
  434.               INT 21h                  ; restore vector
  435.               POP DS                   ; restore DS and DX
  436.               POP DX
  437.               CLC                      ; clear carry
  438.               RET
  439. RemoveErr:    LEA DX,RemoveErrMsg2
  440.               CMP AX,7
  441.               JE RET
  442.               LEA DX,RemoveErrMsg3
  443.               RET
  444.  
  445.  
  446. ; Key repeat rate factor is KeySpeed (1..4) where 4 is fastest. This translates
  447. ; into these port values: AL:  1=27, 5=18, 10=10, 16=7.5  (output)
  448. ;                   KeySpeed:   4     3      2      1     (input)
  449.  
  450. QuickKey:     STC
  451.               LEA DX,NoATmsg           ; no, exit with message
  452.               CMP CPU286,True          ; is this an AT
  453.               JNE RET                  ; no, exit
  454.               LEA DX,SpeedMsg
  455.               MOV AH,9
  456.               INT 21h                  ; print "Key repeat rate is"
  457.               MOV BL,KeySpeed
  458.               DEC BL                   ; BL = 0..3
  459.               SHL BL,1                 ; BL = 2*BL use as index
  460.               XOR BH,BH
  461.               MOV DX,MsgOfs[BX]        ; print cps rate
  462.               MOV AH,9
  463.               INT 21h
  464.  
  465.               MOV AL,KeySpeed          ; KeySpeed = 1..4
  466.               LEA BX,KeySpeedTable     ; load table index, AL = keyspeed 0..4
  467.               XLAT KeySpeedTable       ; AL = speed factor
  468.               MOV BL,AL                ; save it in BL
  469.               
  470.               MOV AL,0F3h
  471.               OUT 60h,AL               ; put keyboard port in "command state"
  472.               MOV CX,100
  473. Delay:        LOOP Delay               ; wait for slow PC-bus to settle
  474.               MOV AL,BL
  475.               OUT 60h,AL               ; set repeat rate
  476.               CLC
  477.               RET
  478.  
  479. CODE ENDS
  480.  
  481.